/*
 *
 * Copyright(c) 2010 Safelayer Secure Communications
 *
 * This is open source software, placed under the terms of the
 * GNU GENERAL PUBLIC LICENSE Version 3.
 * Please see: http://www.gnu.org/licenses/gpl-3.0.txt
 * 
 * Permission to use, copy, modify, and distribute this software
 * for any purpose and without fee is hereby granted, provided
 * that the above copyright notices appear in all copies and that
 * both the copyright notice and this permission notice appear in
 * supporting documentation.
 * 
 */
package com.neuralnoise.foaf.core;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.util.ResourceUtils;

/**
 * Class to define WrappedContacts.
 * 
 * @author victor.martinez <swtp@safelayer.com>
 * 
 */
public class WrappedContact {

	/** The result resource of the merge process **/
	private Resource result = null;;

	/** Indexes the listResources are related to **/
	private Set<Integer> indexModelsBelongsTo = new LinkedHashSet<Integer>();

	private static List<Rule> trustRules;

	private static List<Rule> untrustRules;

	static {
		// trust rules
		trustRules = new ArrayList<Rule>();
		trustRules.add(new AimChatIdRule());
		trustRules.add(new IcqChatIdRule());
		trustRules.add(new JabberIdRule());
		trustRules.add(new MboxRule());
		trustRules.add(new MboxSha1sumRule());
		trustRules.add(new MsnChatIdRule());
		trustRules.add(new YahooChatIdRule());
		trustRules.add(new SeeAlsoRule());
		trustRules.add(new HomePageRule());
		// untrust rules
		untrustRules = new ArrayList<Rule>();
		untrustRules.add(new FirstNameMatchRule());
		untrustRules.add(new GivenNameMatchRule());
		untrustRules.add(new NameMatchRule());
		untrustRules.add(new NameRule());
	}

	// Constructors

	public WrappedContact() {

	}

	public WrappedContact(Resource resource, int index) {
		result = resource;
		indexModelsBelongsTo.add(index);
		result.asNode().hashCode();
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((this.result == null) ? 0 : this.result.asNode().hashCode());
		return result;
	}

	public boolean equalsContacts(Object obj, boolean trustSmushing) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		WrappedContact other = (WrappedContact) obj;
		if (result == null) {
			if (other.result != null)
				return false;
		}
		else if (!equalsApplyingRules(other, trustSmushing))
			return false;
		return true;
	}

	/**
	 * Merge the given {@link WrappedContact} with this instance.
	 * 
	 * @param other The input WrappedContact to merge with this instance.
	 * @return The WrappedContact merged.
	 */
	public WrappedContact merge(WrappedContact other) {
		this.result = mergeResources(other);
		this.indexModelsBelongsTo.addAll(other.getIndexModelsBelongsTo());
		return this;
	}

	

	// Helpers -----------------------------------------------------------------------------------
	
	private Resource mergeResources(WrappedContact other) {
		List<Resource> resourcesToMerge = new ArrayList<Resource>();
		resourcesToMerge.add(result);
		resourcesToMerge.add(other.getResult());
		Model model = MergeEngine.mergeResources(resourcesToMerge);
		Resource resourceMerged = model.getResource(MergeEngine.TEMPORAL_PERSON_URI);
		Resource resourceMergeAnnonymous = ResourceUtils.renameResource(resourceMerged, ""); //convert to annon resource
		return resourceMergeAnnonymous;
	}

	private boolean equalsApplyingRules(WrappedContact other, boolean trustSmushing) {
		if(trustSmushing) {
			return applyTrustRules(other);
		}
		else {
			return applyAllRules(other);
		}
	}
	
	// Getters -----------------------------------------------------------------------------
	
	private boolean applyAllRules(WrappedContact other) {
		List<Rule> allRules = new ArrayList<Rule>();
		allRules.addAll(trustRules);
		allRules.addAll(untrustRules);
		for(Rule rule: allRules) {
			if(rule.equals(this.result, other.getResult()))
				return true;
		}
		return false;
	}

	private boolean applyTrustRules(WrappedContact other) {
		for(Rule rule: trustRules){
			if(rule.equals(this.result, other.getResult()))
				return true;
		}
		return false;
	}

	/**
	 * @return the resource result wrapp.
	 */
	public Resource getResult() {
		return result;
	}
	
	/**
	 * @return the indexModelsBelongsTo.
	 */
	public Set<Integer> getIndexModelsBelongsTo() {
		return indexModelsBelongsTo;
	}

	
}
